#
# Contains macros to handle library dependencies.
#


# DRUNTIME_LIBRARIES_DLOPEN
# -----------------------
# Autodetect and add dl library to LIBS if necessary.
AC_DEFUN([DRUNTIME_LIBRARIES_DLOPEN],
[
  # Libtool has already checked this, so re-use the inferred dlopen lib.
  AS_IF([test "x$enable_dlopen" = "xyes" && test -n "$lt_cv_dlopen_libs"], [
    LIBS="$LIBS $lt_cv_dlopen_libs"
  ], [
  ])
])


# DRUNTIME_LIBRARIES_NET
# -----------------------
# Autodetect and add networking library to LIBS if necessary.
AC_DEFUN([DRUNTIME_LIBRARIES_NET],
[
  dnl Check for the existence of the -lsocket and -lnsl libraries.
  dnl The order here is important, so that they end up in the right
  dnl order in the command line generated by make.  Here are some
  dnl special considerations:
  dnl 1. Use "connect" and "accept" to check for -lsocket, and
  dnl    "gethostbyname" to check for -lnsl.
  dnl 2. Use each function name only once:  can't redo a check because
  dnl    autoconf caches the results of the last check and won't redo it.
  dnl 3. Use -lnsl and -lsocket only if they supply procedures that
  dnl    aren't already present in the normal libraries.
  dnl 4. On some systems, can't use -lsocket without -lnsl too.
  dnl    To get around this problem, check for both libraries together
  dnl    if -lsocket doesn't work by itself.
  druntime_check_both=no
  AC_CHECK_FUNC(connect, ,
	[AC_CHECK_LIB(socket, connect,
	 LIBS="$LIBS -lsocket", druntime_check_both=yes)])
  if test "$druntime_check_both" = "yes"; then
    druntime_old_libs=$LIBS
    LIBS="$LIBS -lsocket -lnsl"
    AC_CHECK_FUNC(accept, , LIBS=$druntime_old_libs)
  fi
  AC_CHECK_FUNC(gethostbyname, ,
	[AC_CHECK_LIB(nsl, gethostbyname, LIBS="$LIBS -lnsl")])
])

# DRUNTIME_LIBRARIES_ZLIB
# -----------------------
# Allow specifying whether to use the system zlib or
# compiling the zlib included in GCC.  Adds substitute
# for LIBZ or adds zlib to LIBS if necessary.
AC_DEFUN([DRUNTIME_LIBRARIES_ZLIB],
[
  AC_LANG_PUSH([C])
  LIBZ=""

  AC_ARG_WITH(target-system-zlib,
    AS_HELP_STRING([--with-target-system-zlib={yes,no,auto}],
                   [use installed libz (default: no)]),,
              [with_target_system_zlib=no])

  case "$with_target_system_zlib" in
    yes|no|auto) ;;
    *) AC_MSG_ERROR([Invalid argument for --with-target-system-zlib]) ;;
  esac

  AC_MSG_CHECKING([for system zlib])
  save_LIBS=$LIBS
  LIBS="$LIBS -lz"
  dnl the link test is not good enough for ARM32 multilib detection,
  dnl first check to link, then to run
  AC_LINK_IFELSE(
    [AC_LANG_PROGRAM([#include <zlib.h>],[gzopen("none", "rb")])],
    [
      AC_RUN_IFELSE([AC_LANG_SOURCE([[
        #include <zlib.h>
        int main() {
          gzFile file = gzopen("none", "rb");
          return 0;
        }
        ]])],
        [system_zlib_found=yes],
        [system_zlib_found=no],
        dnl no system zlib for cross builds ...
        [system_zlib_found=no]
      )
    ],
    [system_zlib_found=no])
  LIBS=$save_LIBS

  if test x$system_zlib_found = xyes && test x$with_target_system_zlib != xno; then
    AC_MSG_RESULT([found])
    LIBS="$LIBS -lz"
  elif test x$system_zlib_found = xno && test x$with_target_system_zlib = xyes; then
    AC_MSG_ERROR([system zlib required but not found])
  else
    AC_MSG_RESULT([just compiled])
    LIBZ=../../zlib/libz_convenience.la
  fi

  AC_SUBST(LIBZ)
  AC_LANG_POP([C])
])

# DRUNTIME_LIBRARIES_ATOMIC
# -------------------------
# Allow specifying whether to use libatomic for atomic support.
AC_DEFUN([DRUNTIME_LIBRARIES_ATOMIC],
[
  AC_ARG_WITH(libatomic,
    AS_HELP_STRING([--without-libatomic],
                   [Do not use libatomic in core.atomic (default: auto)]))

  DCFG_HAVE_LIBATOMIC=false
  LIBATOMIC=
  AS_IF([test "x$enable_libatomic" != "xno" && test "x$with_libatomic" != "xno"], [
    DCFG_HAVE_LIBATOMIC=true
    LIBATOMIC=../../libatomic/libatomic_convenience.la
  ], [
    AC_MSG_CHECKING([for libatomic])
    AC_MSG_RESULT([disabled])
  ])

  AC_SUBST(DCFG_HAVE_LIBATOMIC)
  AC_SUBST(LIBATOMIC)
])

# DRUNTIME_LIBRARIES_BACKTRACE
# ---------------------------
# Allow specifying whether to use libbacktrace for backtrace support.
# Adds subsitute for BACKTRACE_SUPPORTED, BACKTRACE_USES_MALLOC,
# and BACKTRACE_SUPPORTS_THREADS.
AC_DEFUN([DRUNTIME_LIBRARIES_BACKTRACE],
[
  AC_LANG_PUSH([C])
  BACKTRACE_SUPPORTED=false
  BACKTRACE_USES_MALLOC=false
  BACKTRACE_SUPPORTS_THREADS=false
  LIBBACKTRACE=""

  AC_ARG_WITH(libbacktrace,
    AS_HELP_STRING([--without-libbacktrace],
                   [Do not use libbacktrace in core.runtime (default: auto)]))

  AS_IF([test "x$enable_libbacktrace" != "xno" && test "x$with_libbacktrace" != "xno"], [
    LIBBACKTRACE=../../libbacktrace/libbacktrace.la

    gdc_save_CPPFLAGS=$CPPFLAGS
    CPPFLAGS="$CPPFLAGS -I../libbacktrace "

    AC_CHECK_HEADER(backtrace-supported.h, have_libbacktrace_h=true,
      have_libbacktrace_h=false)

    if $have_libbacktrace_h; then
      AC_MSG_CHECKING([libbacktrace: BACKTRACE_SUPPORTED])
      AC_EGREP_CPP(FOUND_LIBBACKTRACE_RESULT_GDC,
      [
      #include <backtrace-supported.h>
      #if BACKTRACE_SUPPORTED
        FOUND_LIBBACKTRACE_RESULT_GDC
      #endif
      ], BACKTRACE_SUPPORTED=true, BACKTRACE_SUPPORTED=false)
      AC_MSG_RESULT($BACKTRACE_SUPPORTED)

      AC_MSG_CHECKING([libbacktrace: BACKTRACE_USES_MALLOC])
      AC_EGREP_CPP(FOUND_LIBBACKTRACE_RESULT_GDC,
      [
      #include <backtrace-supported.h>
      #if BACKTRACE_USES_MALLOC
        FOUND_LIBBACKTRACE_RESULT_GDC
      #endif
      ], BACKTRACE_USES_MALLOC=true, BACKTRACE_USES_MALLOC=false)
      AC_MSG_RESULT($BACKTRACE_USES_MALLOC)

      AC_MSG_CHECKING([libbacktrace: BACKTRACE_SUPPORTS_THREADS])
      AC_EGREP_CPP(FOUND_LIBBACKTRACE_RESULT_GDC,
      [
      #include <backtrace-supported.h>
      #if BACKTRACE_SUPPORTS_THREADS
        FOUND_LIBBACKTRACE_RESULT_GDC
      #endif
      ], BACKTRACE_SUPPORTS_THREADS=true, BACKTRACE_SUPPORTS_THREADS=false)
      AC_MSG_RESULT($BACKTRACE_SUPPORTS_THREADS)
    fi
    CPPFLAGS=$gdc_save_CPPFLAGS
  ], [
    AC_MSG_CHECKING([for libbacktrace])
    AC_MSG_RESULT([disabled])
  ])

  AC_SUBST(LIBBACKTRACE)
  AC_SUBST(BACKTRACE_SUPPORTED)
  AC_SUBST(BACKTRACE_USES_MALLOC)
  AC_SUBST(BACKTRACE_SUPPORTS_THREADS)
  AC_LANG_POP([C])
])

# DRUNTIME_LIBRARIES_CLIB
# -----------------------
# Perform various feature checks on the C library.
AC_DEFUN([DRUNTIME_LIBRARIES_CLIB],
[
  AC_LANG_PUSH([C])
  DCFG_HAVE_QSORT_R=false
  AC_CHECK_FUNC(qsort_r, [DCFG_HAVE_QSORT_R=true])
  AC_SUBST(DCFG_HAVE_QSORT_R)
  AC_LANG_POP([C])
])

# DRUNTIME_LIBRARIES_UCONTEXT
# ------------------------------
# Autodetect and add ucontext library to LIBS if necessary.
# This is only required if fiber_switchContext does not have
# its own internal asm implementation.
AC_DEFUN([DRUNTIME_LIBRARIES_UCONTEXT],
[
  # Keep this in sync with core/thread.d, set druntime_fiber_asm_external to
  # "yes" for targets that have 'version = AsmExternal'.
  druntime_fiber_asm_external=no
  case "$target_cpu" in
    aarch64* | \
    arm* | \
    i[[34567]]86|x86_64 | \
    powerpc)
      druntime_fiber_asm_external=yes
      ;;
  esac
  if test "$druntime_fiber_asm_external" = no; then
    AC_SEARCH_LIBS([swapcontext], [c ucontext], [],
      AC_MSG_ERROR([swapcontext required but not found]))
  fi
])

# DRUNTIME_LIBRARIES_VALGRIND
# ------------------------------
# Allow specifying whether to use valgrind integration in the GC, which enables
# the D run-time to communicate which memory access operations are valid.
# This is only required if `--enable-libphobos-checking=valgrind' was seen.
AC_DEFUN([DRUNTIME_LIBRARIES_VALGRIND],
[
  AC_CHECK_HEADERS(stddef.h stdlib.h)

  AC_CHECK_HEADER(valgrind.h, have_valgrind_h=yes, have_valgrind_h=no)

  AC_MSG_CHECKING(for VALGRIND_DISCARD in <valgrind/memcheck.h>)
  AC_PREPROC_IFELSE([AC_LANG_SOURCE(
    [[#include <valgrind/memcheck.h>
  #ifndef VALGRIND_DISCARD
  #error VALGRIND_DISCARD not defined
  #endif]])],
    [have_valgrind_memcheck_h=yes],
    [have_valgrind_memcheck_h=no])
  AC_MSG_RESULT($have_valgrind_memcheck_h)
  AC_MSG_CHECKING(for VALGRIND_DISCARD in <memcheck.h>)
  AC_PREPROC_IFELSE([AC_LANG_SOURCE(
    [[#include <memcheck.h>
  #ifndef VALGRIND_DISCARD
  #error VALGRIND_DISCARD not defined
  #endif]])],
    [have_memcheck_h=yes],
    [have_memcheck_h=no])
  AC_MSG_RESULT($have_memcheck_h)

  if test x$VALGRIND_FLAG != x ; then
    AC_DEFINE(ENABLE_VALGRIND_CHECKING, 1,
        [Define to enable to integrate valgrind (a memory checker) in the GC.])
  fi
  if test $have_valgrind_memcheck_h = yes; then
    AC_DEFINE(HAVE_VALGRIND_MEMCHECK_H, 1,
        [Define if valgrind's valgrind/memcheck.h header is installed.])
  fi
  if test $have_memcheck_h = yes; then
    AC_DEFINE(HAVE_MEMCHECK_H, 1,
        [Define if valgrind's memcheck.h header is installed.])
  fi

  if test x$VALGRIND_FLAG != x; then
    if (test $have_valgrind_h = no \
        && test $have_memcheck_h = no \
        && test $have_valgrind_memcheck_h = no); then
      AC_MSG_ERROR([*** valgrind checking requested, but
*** Can't find valgrind/memcheck.h, memcheck.h or valgrind.h])
    fi
  fi
])
